package com.devilvan.betrice.europeacademy.service.impl;

import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.devilvan.betrice.annotation.BetriceRunTime;
import com.devilvan.betrice.download.component.BetriceDownloadComponent;
import com.devilvan.betrice.download.pojo.PictureSuffixConstant;
import com.devilvan.betrice.europeacademy.constant.EuropeAcademyRedisConstant;
import com.devilvan.betrice.europeacademy.entity.FindAllAvatarEntity;
import com.devilvan.betrice.request.component.HttpClientComponent;
import com.devilvan.betrice.request.component.JsoupComponent;
import com.devilvan.betrice.common.BetriceResultCode;
import com.devilvan.betrice.europeacademy.constant.EuropeAcademyConstant;
import com.devilvan.betrice.europeacademy.entity.EuropeAcademyExportEntity;
import com.devilvan.betrice.europeacademy.mapper.EuropeAcademyHeaderMapper;
import com.devilvan.betrice.europeacademy.po.EuropeAcademyAwardPo;
import com.devilvan.betrice.europeacademy.po.EuropeAcademyHeaderPo;
import com.devilvan.betrice.europeacademy.po.EuropeAcademyResumePo;
import com.devilvan.betrice.europeacademy.po.EuropeAcademyScholarshipPo;
import com.devilvan.betrice.europeacademy.repository.EuropeAcademyHeaderRepository;
import com.devilvan.betrice.europeacademy.service.EuropeAcademyAwardService;
import com.devilvan.betrice.europeacademy.service.EuropeAcademyHeaderService;
import com.devilvan.betrice.europeacademy.service.EuropeAcademyResumeService;
import com.devilvan.betrice.europeacademy.service.EuropeAcademyScholarshipService;
import com.devilvan.betrice.europeacademy.vo.EuropeAcademyHeaderVo;
import com.devilvan.betrice.export.component.EasyexcelComponent;
import com.devilvan.betrice.export.pojo.EasyexcelWriteDto;
import com.devilvan.betrice.util.UCopy;
import com.devilvan.betrice.common.BetriceResultVo;
import com.devilvan.betrice.util.UEmpty;
import org.apache.http.client.methods.HttpRequestBase;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.annotation.Nonnull;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Evad.Wu
 * @Description 欧洲学术成员 基本信息 业务逻辑类
 * @date 2022-09-06
 */
@Service
public class EuropeAcademyHeaderServiceImpl
        extends ServiceImpl<EuropeAcademyHeaderMapper, EuropeAcademyHeaderPo>
        implements EuropeAcademyHeaderService {
    @SuppressWarnings("FieldCanBeLocal")
    private final String SAVE_PATH_PREFIX = "D:\\Mine\\杂物\\Europo_Academy_Membership_Avatar\\";

    @Resource(name = "jsoupComponent")
    private JsoupComponent jsoupComponent;
    @Resource(name = "betriceRedisTemplate")
    private RedisTemplate<String, Object> redisTemplate;
    @Resource(name = "easyexcelComponent")
    private EasyexcelComponent easyexcelComponent;
    @Resource(name = "betriceDownloadComponent")
    private BetriceDownloadComponent betriceDownloadComponent;
    @Resource(name = "httpClientComponent")
    private HttpClientComponent httpClientComponent;

    @Resource(name = "europeAcademyHeaderRepository")
    private EuropeAcademyHeaderRepository europeAcademyHeaderRepository;
    @Resource(name = "europeAcademyHeaderMapper")
    private EuropeAcademyHeaderMapper europeAcademyHeaderMapper;
    @Resource(name = "europeAcademyResumeServiceImpl")
    private EuropeAcademyResumeService europeAcademyResumeService;
    @Resource(name = "europeAcademyScholarshipServiceImpl")
    private EuropeAcademyScholarshipService europeAcademyScholarshipService;
    @Resource(name = "europeAcademyAwardServiceImpl")
    private EuropeAcademyAwardService europeAcademyAwardService;

    @Override
    @BetriceRunTime
    @Async(value = "threadPoolExecutor")
    public CompletableFuture<BetriceResultVo<EuropeAcademyHeaderPo>> doEuropeAcademy(@Nonnull String url) {
        BetriceResultVo<EuropeAcademyHeaderPo> betriceResultVo = new BetriceResultVo<>(false);
        try {
            EuropeAcademyHeaderVo europeAcademyHeaderVo = this.europeAcademyHeaderCrawler(url);
            Long membershipId = europeAcademyHeaderVo.getMembershipId();
            boolean flag = this.isMembershipExists(membershipId);
            if (flag) {
                europeAcademyAwardService.deleteByMembershipId(membershipId);
                europeAcademyScholarshipService.deleteByMembershipId(membershipId);
                europeAcademyResumeService.deleteByMembershipId(membershipId);
                this.deleteByMembershipId(membershipId);
            }
            // 基本信息
            EuropeAcademyHeaderPo europeAcademyHeaderPo = new EuropeAcademyHeaderPo();
            UCopy.fullCopy(europeAcademyHeaderVo, europeAcademyHeaderPo, "resumeList", "scholarshipList", "awardList");
            EuropeAcademyHeaderPo saveUpdate = this.saveUpdate(europeAcademyHeaderPo);
            // 奖项荣誉
            List<String> awardList = europeAcademyHeaderVo.getAwardList();
            List<EuropeAcademyAwardPo> europeAcademyAwardPoList = this.checkAssemAwardList(membershipId, awardList);
            List<EuropeAcademyAwardPo> saveAwardPoList = europeAcademyAwardService.saveUpdateBatch(europeAcademyAwardPoList);
            saveUpdate.setAwardPoList(saveAwardPoList);
            // 研究领域
            List<String> scholarshipList = europeAcademyHeaderVo.getScholarshipList();
            List<EuropeAcademyScholarshipPo> europeAcademyScholarshipPoList = this.checkAssemScholarship(membershipId, scholarshipList);
            List<EuropeAcademyScholarshipPo> saveScholarshipPoList = europeAcademyScholarshipService.saveUpdateBatch(europeAcademyScholarshipPoList);
            saveUpdate.setScholarshipPoList(saveScholarshipPoList);
            // 履历信息
            List<String> resumeList = europeAcademyHeaderVo.getResumeList();
            List<EuropeAcademyResumePo> europeAcademyResumePoList = this.checkAssemResumeList(membershipId, resumeList);
            List<EuropeAcademyResumePo> saveResumePoList = europeAcademyResumeService.saveUpdateBatch(europeAcademyResumePoList);
            saveUpdate.setResumePoList(saveResumePoList);
            betriceResultVo.setSuccess(true);
            betriceResultVo.result(BetriceResultCode.SUCCESS_200.getCode(), "操作成功", saveUpdate);
        } catch (Exception e) {
            e.printStackTrace();
            ReentrantLock lock = new ReentrantLock();
            lock.lock();
            try {
                redisTemplate.opsForList().rightPush(EuropeAcademyRedisConstant.KEY_EUROPE_ACADEMY_MEMBER_EXCEPTION, url);
            } catch (Exception exception) {
                exception.printStackTrace();
            } finally {
                lock.unlock();
            }
            betriceResultVo.result(BetriceResultCode.FAILED_500.getCode(), e.toString());
        }
        return CompletableFuture.completedFuture(betriceResultVo);
    }

    private EuropeAcademyHeaderVo europeAcademyHeaderCrawler(String url) {
        EuropeAcademyHeaderVo europeAcademyHeaderVo = new EuropeAcademyHeaderVo();
        Element body = jsoupComponent.getBody(url);
        String name = body.select("#pagecontent>*:first-child").text().replace("#", "");
        String avatar = body.select("div[class='image_default']>a").attr("href");
        europeAcademyHeaderVo.setName(name);
        europeAcademyHeaderVo.setAvatar(avatar);
        List<String> membershipBasicInfoList = body.select("table[class='memberinfo']>tbody>tr").eachText();
        copyToEuropeAcademyHeaderVo(europeAcademyHeaderVo, collToMap(membershipBasicInfoList));
        Elements ulList = body.select("#pagecontent ul");
        for (int i = 0; i < ulList.size(); i++) {
            if (i == 0) {
                List<String> resumeList = ulList.get(i).select("li").eachText();
                europeAcademyHeaderVo.setResumeList(resumeList);
            } else if (i == 1) {
                List<String> scholarshipList = ulList.get(i).select("li").eachText();
                europeAcademyHeaderVo.setScholarshipList(scholarshipList);
            } else if (i == 2) {
                List<String> awardList = ulList.get(i).select("li").eachText();
                europeAcademyHeaderVo.setAwardList(awardList);
            }
        }
        return europeAcademyHeaderVo;
    }

    private List<EuropeAcademyResumePo> checkAssemResumeList(Long membershipId, List<String> resumeList) {
        List<EuropeAcademyResumePo> europeAcademyResumePoList = new ArrayList<>();
        if (Optional.ofNullable(resumeList).isPresent()) {
            europeAcademyResumePoList = resumeList.stream().map(m -> {
                EuropeAcademyResumePo europeAcademyResumePo = new EuropeAcademyResumePo();
                europeAcademyResumePo.setMembershipId(membershipId);
                europeAcademyResumePo.setResume(m);
                return europeAcademyResumePo;
            }).toList();
        }
        return europeAcademyResumePoList;
    }

    private List<EuropeAcademyScholarshipPo> checkAssemScholarship(Long membershipId, List<String> scholarshipList) {
        List<EuropeAcademyScholarshipPo> europeAcademyScholarshipPoList = new ArrayList<>();
        if (Optional.ofNullable(scholarshipList).isPresent()) {
            europeAcademyScholarshipPoList = scholarshipList.stream().map(m -> {
                EuropeAcademyScholarshipPo europeAcademyScholarshipPo = new EuropeAcademyScholarshipPo();
                europeAcademyScholarshipPo.setMembershipId(membershipId);
                europeAcademyScholarshipPo.setScholarship(m);
                return europeAcademyScholarshipPo;
            }).toList();
        }
        return europeAcademyScholarshipPoList;
    }

    private List<EuropeAcademyAwardPo> checkAssemAwardList(Long membershipId, List<String> awardList) {
        List<EuropeAcademyAwardPo> europeAcademyAwardPoList = new ArrayList<>();
        if (Optional.ofNullable(awardList).isPresent()) {
            europeAcademyAwardPoList = awardList.stream().map(m -> {
                EuropeAcademyAwardPo europeAcademyAwardPo = new EuropeAcademyAwardPo();
                europeAcademyAwardPo.setMembershipId(membershipId);
                europeAcademyAwardPo.setAward(m);
                return europeAcademyAwardPo;
            }).toList();
        }
        return europeAcademyAwardPoList;
    }

    @Override
    public EuropeAcademyHeaderPo saveUpdate(EuropeAcademyHeaderPo europeAcademyHeaderPo) {
        return europeAcademyHeaderRepository.saveAndFlush(europeAcademyHeaderPo);
    }

    @Override
    public List<EuropeAcademyHeaderPo> saveUpdateBatch(List<EuropeAcademyHeaderPo> list) {
        return europeAcademyHeaderRepository.saveAllAndFlush(list);
    }

    @Override
    public boolean isMembershipExists(Long membershipId) {
        LambdaQueryWrapper<EuropeAcademyHeaderPo> queryWrapper = new QueryWrapper<EuropeAcademyHeaderPo>().lambda();
        queryWrapper.eq(EuropeAcademyHeaderPo::getMembershipId, membershipId);
        return this.baseMapper.exists(queryWrapper);
    }

    @Override
    public void deleteByMembershipId(Long membershipId) {
        LambdaUpdateWrapper<EuropeAcademyHeaderPo> updateWrapper = new UpdateWrapper<EuropeAcademyHeaderPo>().lambda();
        updateWrapper.eq(EuropeAcademyHeaderPo::getMembershipId, membershipId);
        this.baseMapper.delete(updateWrapper);
    }

    @Override
    public EuropeAcademyHeaderPo findByMembershipId(Long membershipId) {
        return europeAcademyHeaderMapper.findByMembershipId(membershipId);
    }

    @Override
    public List<EuropeAcademyHeaderPo> findByMembershipIdList(List<Long> membershipIdList) {
        return europeAcademyHeaderMapper.findByMembershipIdList(membershipIdList);
    }

    @Override
    public List<EuropeAcademyHeaderPo> findEuropeAcademyHeaderPage(Page<EuropeAcademyHeaderPo> page) {
        return europeAcademyHeaderMapper.findEuropeAcademyHeaderPage(page);
    }

    @Override
    public BetriceResultVo<Void> doExportExcelByMembershipIdList(EasyexcelWriteDto easyexcelWriteDto, List<Long> membershipIdList) {
        BetriceResultVo<Void> betriceResultVo = new BetriceResultVo<>(false);
        ExcelWriter excelWriter = null;
        try {
            List<EuropeAcademyHeaderPo> headerPoList = this.findByMembershipIdList(membershipIdList);
            List<EuropeAcademyExportEntity> entityList = this.headerPoCastToExportEntity(headerPoList);
            excelWriter = easyexcelComponent.doExcelWriter(easyexcelWriteDto);
            WriteSheet writeSheet = easyexcelComponent.doWriteSheet(easyexcelWriteDto.getSheet());
            easyexcelComponent.doExport(excelWriter, writeSheet, entityList);
            betriceResultVo.setSuccess(true);
            betriceResultVo.setHandleCount(entityList.size());
            betriceResultVo.result(BetriceResultCode.SUCCESS_200.getCode(), "导出成功！");
        } catch (Exception e) {
            e.printStackTrace();
            betriceResultVo.result(BetriceResultCode.SUCCESS_200.getCode(), "导出失败！" + e);
        } finally {
            easyexcelComponent.doFinish(excelWriter);
        }
        return betriceResultVo;
    }

    @Override
    public BetriceResultVo<Void> doExportExcelAll(EasyexcelWriteDto easyexcelWriteDto) {
        BetriceResultVo<Void> betriceResultVo = new BetriceResultVo<>(false);
        ExcelWriter excelWriter = easyexcelComponent.doExcelWriter(easyexcelWriteDto);
        WriteSheet writeSheet = easyexcelComponent.doWriteSheet(easyexcelWriteDto.getSheet());
        try {
            int currentPage = 1;
            int total = 0;
            while (true) {
                Page<EuropeAcademyHeaderPo> page = new Page<>(currentPage, 1000);
                List<EuropeAcademyHeaderPo> headerPoList = this.findEuropeAcademyHeaderPage(page);
                if (headerPoList.isEmpty()) {
                    break;
                }
                List<EuropeAcademyExportEntity> entityList = this.headerPoCastToExportEntity(headerPoList);
                excelWriter.write(entityList, writeSheet);
                currentPage++;
                total += entityList.size();
            }
            betriceResultVo.setSuccess(true);
            betriceResultVo.setHandleCount(total);
            betriceResultVo.result(BetriceResultCode.SUCCESS_200.getCode(), "导出成功！");
        } catch (Exception e) {
            e.printStackTrace();
            betriceResultVo.result(BetriceResultCode.SUCCESS_200.getCode(), "导出失败！" + e);
        } finally {
            easyexcelComponent.doFinish(excelWriter);
        }
        return betriceResultVo;
    }

    @Override
    public List<FindAllAvatarEntity> findAllMembershipAvatar() {
        return europeAcademyHeaderMapper.findAllAvatar().stream()
                .filter(f -> UEmpty.isNotEmpty(f.getAvatar())).toList();
    }

    @Override
    @BetriceRunTime
    @Async(value = "threadPoolExecutor")
    public CompletableFuture<Boolean> downloadAllMembershipAvatar(FindAllAvatarEntity entity) {
        try {
            HttpRequestBase request = httpClientComponent.generateHttpRequest(RequestMethod.GET, entity.getAvatar());
            String filePath = SAVE_PATH_PREFIX + entity.getMembershipId() + "_" + entity.getName() + PictureSuffixConstant.PNG.getValue();
            betriceDownloadComponent.download(request, filePath);
            return CompletableFuture.completedFuture(true);
        } catch (Exception e) {
            e.printStackTrace();
            redisTemplate.opsForList().leftPush(EuropeAcademyRedisConstant.KEY_EUROPE_ACADEMY_AVATAR_EXCEPTION, entity.getAvatar());
        }
        return CompletableFuture.completedFuture(false);
    }

    private List<EuropeAcademyExportEntity> headerPoCastToExportEntity(List<EuropeAcademyHeaderPo> headerPoList) {
        return headerPoList.stream().map(m -> {
            EuropeAcademyExportEntity europeAcademyExportEntity = new EuropeAcademyExportEntity();
            UCopy.fullCopy(m, europeAcademyExportEntity, "resumeList", "scholarshipList", "awardList");
            List<EuropeAcademyAwardPo> awardPoList = m.getAwardPoList();
            if (Optional.ofNullable(awardPoList).isPresent()) {
                StringBuilder sb = new StringBuilder();
                int count = 1;
                int len = awardPoList.size();
                for (int i = 0; i < len; i++) {
                    if (i + 1 >= len) {
                        sb.append(count).append(". ").append(awardPoList.get(i).getAward());
                    } else {
                        sb.append(count).append(". ").append(awardPoList.get(i).getAward()).append("\n");
                    }
                    count++;
                }
                europeAcademyExportEntity.setAward(sb.toString());
            }
            List<EuropeAcademyScholarshipPo> scholarshipPoList = m.getScholarshipPoList();
            if (Optional.ofNullable(scholarshipPoList).isPresent()) {
                StringBuilder sb = new StringBuilder();
                int count = 1;
                int len = scholarshipPoList.size();
                for (int i = 0; i < len; i++) {
                    if (i + 1 >= len) {
                        sb.append(count).append(". ").append(scholarshipPoList.get(i).getScholarship());
                    } else {
                        sb.append(count).append(". ").append(scholarshipPoList.get(i).getScholarship()).append("\n");
                    }
                    count++;
                }
                europeAcademyExportEntity.setScholarship(sb.toString());
            }
            List<EuropeAcademyResumePo> resumePoList = m.getResumePoList();
            if (Optional.ofNullable(resumePoList).isPresent()) {
                StringBuilder sb = new StringBuilder();
                int count = 1;
                int len = resumePoList.size();
                for (int i = 0; i < len; i++) {
                    if (i + 1 >= len) {
                        sb.append(count).append(". ").append(resumePoList.get(i).getResume());
                    } else {
                        sb.append(count).append(". ").append(resumePoList.get(i).getResume()).append("\n");
                    }
                    count++;
                }
                europeAcademyExportEntity.setResume(sb.toString());
            }
            return europeAcademyExportEntity;
        }).toList();
    }

    private Map<String, String> collToMap(List<String> membershipBasicInfoList) {
        Map<String, String> map = new HashMap<>(16);
        for (String s : membershipBasicInfoList) {
            String[] split = s.split(": ");
            if (split.length > 1) {
                map.put(split[0], split[1]);
            }
        }
        return map;
    }

    private void copyToEuropeAcademyHeaderVo(EuropeAcademyHeaderVo europeAcademyHeaderVo, Map<String, String> map) {
        Set<Map.Entry<String, String>> entrySet = map.entrySet();
        for (Map.Entry<String, String> entry : entrySet) {
            if (EuropeAcademyConstant.MEMBERSHIP_NUMBER.equals(entry.getKey())) {
                europeAcademyHeaderVo.setMembershipId(Long.valueOf(entry.getValue()));
            } else if (EuropeAcademyConstant.MEMBERSHIP_TYPE.equals(entry.getKey())) {
                europeAcademyHeaderVo.setMemberType(entry.getValue());
            } else if (EuropeAcademyConstant.SECTION.equals(entry.getKey())) {
                europeAcademyHeaderVo.setSection(entry.getValue());
            } else if (EuropeAcademyConstant.AFFILIATED_SECTION.equals(entry.getKey())) {
                europeAcademyHeaderVo.setAffiliatedSection(entry.getValue());
            } else if (EuropeAcademyConstant.ELECTED.equals(entry.getKey())) {
                europeAcademyHeaderVo.setElected(entry.getValue());
            } else if (EuropeAcademyConstant.MAIN_COUNTRY_OF_RESIDENCE.equals(entry.getKey())) {
                europeAcademyHeaderVo.setMainResidence(entry.getValue());
            } else if (EuropeAcademyConstant.HOME_PAGE.equals(entry.getKey())) {
                europeAcademyHeaderVo.setHomePage(entry.getValue());
            } else if (EuropeAcademyConstant.ORCID.equals(entry.getKey())) {
                europeAcademyHeaderVo.setOrcId(entry.getValue());
            }
        }
    }
}
